//Spring 概述

1. 两个基础模块，IOC和Aop

2. Spring 是一个轻量级控制反转(IOC)和面向切面的容器框架，它主要是为了解决企业应用开发的复杂性而诞生的
	主要优势:分层模块，分层的，一键式的轻量级开发框架
	目的:解决企业应用开发的复杂性
	功能:使用基本的JavaBean代替EJB
	范围:任何Java应用程序
	
	使用Spring给开发带来的好处；
	*可以有效组织中间层对象
	*使用统一的配置文件
	*促进良好编程习惯，减少编程代价
	*易于单元测试
	*使EJB成为一种备选
	*为数据存取提供了一套框架
	
	*方便解耦，简化开发
	*AOP编程的支持
	*声明式事务的支持
	*方便程序的测试
	*方便集成各种优秀框架
	*降低JavaEE API的使用难度
	*Spring的源码是经典学习范例
	
3. Spring的核心模块
	a、核心容器(Spring Core)
	b、应用上下文(Spring Context)
	c、AOP模块(Spring AOP)
	d、JDBC和DAO模块(Spring DAO)
	e、对象实体映射(Spring ORM)
	f、Web模块(Spring Web)
	g、MVC模块(Spring Web MVC)
	
	 
4. Spring IOC
	a、IOC(Inversion Of Control,控制反转)是Spring的核心，贯穿始终。所谓IOC，对于spring框架来说，就是由spring来负责控制对象的生命周期和对象之间的关系
	b、IOC的另外的名字叫做依赖注入(Dependency Injection)，所谓的依赖注入，就是由IOC容器在运行期间，动态地将某种依赖关系注入到对象之中。所以，依赖注入(DI)和
		控制反转(IOC)是从不同角度描述同一件事情，就是指通过引入IOC容器，利用依赖关系注入的方式，实现对象之间的解耦。
	c、IOC通俗的理解如下:
		(1)IOC控制反转:说的是创建对象实例的控制权从代码控制剥离到IOC容器控制，实际就是xml文件控制，侧重于原理
		(2)DI依赖注入:说的是创建对象实例时，为这个对象注入属性值或其他对象实例，侧重于实现

5. Spring AOP 
	a、AOP的基本概念:(Aspect Oriented Programming)面向切面编程。AOP是OOP的有益补充，研究动态领域
	b、AOP主要功能，系统级 （日志记录，性能统计，安全控制，事务管理，异常处理）
	c、AOP代理其实是由AOP框架动态生成的一个对象，该对象可作为目标对象使用，AOP代理所包含的方法与目标对象的方法
	d、关键概念:切面-Aspect，连接点-Join Point，通知-Advice，切入点-Point Cut，引入-Introduction，目标对象-Target object，AOP代理-AOP Proxy，织入Weaving 
	e、AOP通俗理解：
		一个组件A,不关心其他常用的服务组件B，但是这个组件A使用组件B的时候，不是组件A自身去调用，而是通过配置等其他方式，比如Spring中可以通过xml配置文件。这样就是的A
		不需要知道服务组件B是怎样的，和其是否存在。A只关心自己的业务逻辑，具体A使用B的时候，配置文件去做，与具体的A组件无关。
	
6. Spring 核心开发包
	*Spring Core
	*Spring Beans 
	*Spring AOP 
	*Spring Context 
	
	提供企业级服务:
	*Spring Aspects
	*Spring Context Support
	*Spring Expression
	*Spring Framework Bom
	*Spring Instrument
	*String Instrument Tomcat 
	*Spring JDBC 
	*Spring JMS
	*Spring Orm：依赖于Spring.dao.jar
	*Spring oxm
	*Spring Struts
	*Spring test
	*Spring tx
	*Spring web
	*Spring webmvc
	*Spring webMVC portlet



1. IOC概述
	IOC是Spring容器的内核，AOP、声明式事物等功能都依赖于此功能
	
	IOC的注入类型:
	
		*构造函数注入:通过调用类的构造函数，将接口实现类通过构造函数变量传入:
			eg：
			public class Wujiandao
			{
				private LiuJiamming ljm;
				//1.注入刘建明的具体扮演者
				public Wujiandao(LiuJiamming ljm)
				{
					this.ljm = ljm;
				}
				
				public void tianTai()
				{
					ljm.declare("我想做一个好人！");
				}
			}
			
			public class Director 
			{
				//2.指定角色的扮演者
				public void direct()
				{
					LiuJiamming ljm = new LiuDeHua()_;
				}
				//3.注入具体扮演者到剧本中
				Wujiandao wjd = new Wujiandao(ljm);
				wjd.tianTai();
			}
	
		*属性注入:通过属性(Setter)方法完成调用类所需依赖的注入，更加灵活方便
			eg:
			public class Wujiandao
			{
				private LiuJiamming ljm;
				//1.属性注入方法
				public void setLjm(LiuJiamming ljm)
				{
					this.ljm = ljm;
				}
				
				public void tianTai()
				{
					ljm.declare("我想做一个好人！");
				}
			}
			
			public class DirectoryManager
			{
				public void direct()
				{
					LiuJianming ljm = new LiuDeHua();
					//2.调用属性Setter方法注入
					wjd.setLjm(ljm);
					wjd.tianTai();
				}
			}
		
		*接口注入:将调用类所有依赖注入的方法抽取到一个接口中，调用类通过实现该接口提供相应的注入方法。
			eg:
			public interface ActorArrangable
			{
				void injectLjm(LiuJiamming ljm);
			}
			
			public class Wujiandao implements ActorArrangable
			{
				private LiuJiamming ljm;
				//1.实现接口方法
				public void injectLjm(LiuJiamming ljm)
				{
					this.ljm = ljm;
				}
				
				public void tianTai()
				{
					ljm.declare("我想做一个好人！");
				}
			}
		
			public class Director
			{
				public void direct() 
				{
					LiuJianming ljm = new LiuDeHua();
					Wujiandao wjd = new Wujiandao();
					wjd.injectLjm(ljm);
					wjd.tianTai();
				}
			}
		
		Spring 作为一个容器，通过配置文件或者注解，描述和类之间的依赖关系，
		自动完成类的初始化工作，下面是对以上实例进行配置的配置文件片段:
		//1.实现类实例化
		<bean id = "ljm" class = "LiuDeHua"/>
		//2.通过ljm-ref建立依赖关系
		<bean id = "wjd" class "Wujiandao" p:ljm-ref = "ljm"/> 
	   </beans>
		
2. Java反射机制
	定义:Java语言允许通过程序化的方式间接对Class的对象实例操作，
	Class文件由类装载器装载后，在JVM中将形成一份描述Class结构的
	元信息对象，通过该元信息对象可以获知Class的结构信息，如构造
	函数、属性和方法等。
		实例见HelloMessage工程下src目录com.nku.chapter03/reflect 中Car.java和ReflectTest.java
		
	ClassLoader:类装载器
		类装载器就是寻找类的字节码文件并构造出类在JVM内部表示的对象组件，主要工作由ClassLoader及子类负责，
		ClassLoader是一个重要的Java运行时系统组件，ClassLoader是一个重要的Java运行时系统组件，它负责在运行
		时查找和装入Class字节码文件。
		
		*工作机制:
			(1)装载:查找和导入Class文件		由ClassLoader及其子类负责，JVM在运行时会产生3个装载器
				分别是根装载器(不是ClassLoader的子类,C语言实现)、EXT.ClassLoader(扩展装载器)、APP.ClassLoader(系统类装载器)
			
			(2)连接:执行校验(检查载入Class文件的数据的正确性)，准备(给类的静态变量分配存储空间)
				和解析(将符号引用转变成直接引用)步骤

			(3)初始化:对类的静态变量、静态代码块实型初始化工作
		
		
		*重要方法(都是接口方法)，位于Java.lang包中
		(1)Class loadClass(String name);//name参数是指定装载器要装载的类的名字，需要使用全限定类名
		(2)Class defineClass(String name,byte[] b,int off,int len);//将Java类的字节数组转换为java.lang.class对象，name参数是对应类的名字
		(3)Class findSystemClass(String name);//从本地文件系统来载入Class文件，本地找不到时会抛出异常ClassNotFound，JVM默认使用的装载机制。
		(4)Class findLoadedClass(String name);//查看CLassLoader是否已经装入了某个类，若已装有，会返回java.lang.class对象，否则返回null，强行装入已存在的类会抛出连接错误
		(5)ClassLoader getParent();//返回一个类装载器的父装载器，除了根装载器，每个装载器有且仅有一个父装载器

	Class反射对象描述类语义结构，可以从Class对象中获取构造函数，成员变量，方法等类元素的反射对象，并以编程的方式通过这些反射对象对目标类对象进行操作。
	这些反射对象类在java.reflect包中定义，下面是最主要的三个反射类:
		
		*Constructor
			 类的构造函数反射类。通过getConstructor()方法可以获得类的所有构造函数的反射对象数组，
			 Constructor的一个主要方法是newInstance()，通过该方法可以创建一个对象类的实例，相当于new关键字。
		
		*Method
			 类方法的反射类。通过getDeclaredMethod()方法，可以获取类的所有方法的反射类对象数组。
			 Method主要方法为invoke(),此外还有获得更多方法信息的方法，如；
				(1)Class getReturnType():获取方法返回值类型
				(2)Class[] getParameterTypes():获取方法入参类型的数组
				(3)Class[] getExceptionTypes():获取方法的异常类型数组
				(4)Annotation[][] getParameterAnnotations():获取方法的注解信息(JDK 5.0 中的新方法)
			 
		*Field
			类的成员字段(变量)的反射类。通过getDeclaredFields()方法可以获取类的成员变量反射对象数组，
			通过这个方法可以获得某个特定名称的成员变量的反射对象
		
		
3. Java反射机制与IOC的关系
		在Spring中，通过IOC可以将实现类、参数信息等配置在其对应的配置文件中，那么当需要更改实现类或参数信息时，
		只需要修改配置文件即可，我们还可以对某对象所需要的其他对象进行注入，这种注入都是在配置文件中做的。
		
		Spring的IOC的实现原理利用的就是Java的反射机制，Spring的工厂类会帮我们完成配置文件的读取、利用反射机制注
		入对象等工作，我们可以通过bean的名称获取对应的对象。
	eg:自己搭建的工厂类，见HelloMessage下的com.nku.chapter03.reflect	
		
4. 资源访问工具类
	JDK所提供的访问资源的类并不能很好的满足各种底层资源的访问需求，因此，Spring设计了一个Resource接口，
	它为应用提供了更强大的访问底层资源的能力。Resource不可或缺，被用来装载各种配置文件和国际化属性文件资源等等
	
	主要方法:
	1. boolean exists() 判断资源是否存在
	2. boolean isOpen() 判断资源是否已经打开
	3. URL getURL() 如果底层资源可以表示成URL，那么该方法将返回对应资源的URL对象
	4. File getFile() 如果底层资源对应一个file文件，那么该方法返回对应资源的File对象
	5. InputStream getInputStream 返回资源对应的输入流
	
	具体实现类:
	1. ByteArrayResource 即二进制数组表示的资源，可以在内存中通过程序来构造
	2. ClassPathResource 即类路径下面的资源，资源以相对于类路径的方式来表示
	3. FileSystemResource 即文件系统资源，资源文件以文件系统路径的方式来表示
	4. InputStreamResource 它对应一个InputStream的资源	
	5. ServletContextResource 主要为了访问Web容器中上下文资源而设计的类，以相对于Web目录
	   的根目录来加载资源，支持以流或URL的方式来访问，在WAR包解包的情况下也可以用File的方式来访问，
	   还支持直接从jar包中访问相关资源
	   
	6. URLResource 封装了java.net.url，用户可已访问任何通过URL表示的资源，如文件系统的资源，http的资源，以及FTP的资源等等
		

//Spring笔记部分
	1. Spring 中的IOC容器: 对应的接口为ApplicationContext
		//Spring Way
		//1. 创建Spring IOC 的容器对象
		ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");//这里指spring的配置文件在类路径的src目录下
		
		//2. 从IOC容器中获取Bean实例	
		HelloWorld helloWorld = (HelloWorld) ctx.getBean("helloWorld");
		
		//3. 调用hello方法
		helloWorld.hello();
		
	2. 配置bean
	***之前service需要某个组件的时候，需要直接获取组件相关接口并直接new出需要的组件；之后有了工厂模式，service只需要获取组件相关接口
		并关联工厂就可以了；而IOC容器使得service所需要的组件都是在需要时被注入的
		
		1) 配置形式: 基于XML文件的方式和基于注解的方式
			a) 在XML文件中通过bean节点来配置bean
				<!-- 
					配置bean
					class: bean的全类名，通过反射的方式在IOC容器中创建Bean，所以要求Bean中必须有无参的构造方法
					id: 标识容器中的bean. id 唯一
				 -->
				<bean id="helloWorld" class="com.nku.mason.spring.beans.HelloWorld">
					<property name="name" value="Spring"></property>
				</bean>
				
			b) 在 Spring IOC 容器读取 Bean 配置创建 Bean 实例之前, 必须对它进行实例化. 只有在容器实例化后, 才可以从 IOC 容器里获取 Bean 实例并使用.
				- Spring 提供了两种类型的 IOC 容器实现. 
					- BeanFactory: IOC 容器的基本实现.
					- ApplicationContext: 提供了更多的高级特性. 是 BeanFactory 的子接口.
				- BeanFactory 是 Spring 框架的基础设施，面向 Spring 本身；ApplicationContext 面向使用 Spring 框架的开发者，
					几乎所有的应用场合都直接使用 ApplicationContext 而非底层的 BeanFactory
				- 无论使用何种方式, 配置文件是相同的.	
				
			c) ApplicationContext 的主要实现类：
				ClassPathXmlApplicationContext：从类路径下加载配置文件
				FileSystemXmlApplicationContext: 从文件系统中加载配置文件
				
			d) 		//Spring Way
					//1. 创建Spring IOC 的容器对象
					ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
					
					//2. 从IOC容器中获取Bean实例	
					//利用id定位到IOC容器中的bean
					HelloWorld helloWorld = (HelloWorld) ctx.getBean("helloWorld");
					//利用类型返回IOC容器中的Bean，但要求IOC容器中必须只能有一个该类型的Bean
			//		HelloWorld helloWorld = ctx.getBean(HelloWorld.class);//用类型信息来获取bean
					System.out.println(helloWorld);
					
					//3. 调用hello方法
					helloWorld.hello();
			
			- 基于注解的方式:
				* 组件扫描(component scanning):  Spring 能够从 classpath 下自动扫描, 侦测和实例化具有特定注解的组件. 
				* 特定组件包括:
					@Component: 基本注解, 标识了一个受 Spring 管理的组件
					@Respository: 标识持久层组件
					@Service: 标识服务层(业务层)组件
					@Controller: 标识表现层组件
				* 对于扫描到的组件, Spring 有默认的命名策略: 使用非限定类名, 第一个字母小写. 
				  也可以在注解中通过 value 属性值标识组件的名称
				
				***当在组件类上使用了特定的注解之后, 还需要在 Spring 的配置文件中声明 <context:component-scan> ：
				  * base-package 属性指定一个需要扫描的基类包，Spring 容器将会扫描这个基类包里及其子包中的所有类. 
				  * 当需要扫描多个包时, 可以使用逗号分隔.
				  如果仅希望扫描特定的类而非基包下的所有类，可使用 resource-pattern 属性过滤特定的类，示例：
					<!-- 指定Spring IOC 容器扫描的包 -->
					<context:component-scan 
						base-package="com.nku.mason.spring.beans.annotation"
						resource-pattern="repository/*.class">
					</context:component-scan>
					
					***Extra:  
					  <context:include-filter> 子节点表示要包含的目标类
					  <context:exclude-filter> 子节点表示要排除在外的目标类
					  <context:component-scan> 下可以拥有若干个 <context:include-filter> 和 <context:exclude-filter> 子节点
					
				- <context:component-scan> 元素还会自动注册 AutowiredAnnotationBeanPostProcessor 实例, 
				  该实例可以自动装配具有 @Autowired 和 @Resource 、@Inject注解的属性.
				  @Autowired 注解自动装配具有兼容类型的单个 Bean属性
					* 构造器, 普通字段(即使是非 public), 一切具有参数的方法都可以应用@Authwired 注解
					* 默认情况下, 所有使用 @Autowired 注解的属性都需要被设置. 当 Spring 找不到匹配的 Bean 装配属性时, 会抛出异常, 若某一属性允许不被设置, 可以设置 @Authwired 注解的 required 属性为 false
					* 默认情况下, 当 IOC 容器里存在多个类型兼容的 Bean 时, 通过类型的自动装配将无法工作. 此时可以在 @Qualifier 注解里提供 Bean 的名称. Spring 允许对方法的入参标注 @Qualifiter 已指定注入 Bean 的名称
				  @Authwired 注解也可以应用在数组类型的属性上, 此时 Spring 将会把所有匹配的 Bean 进行自动装配.
				  @Authwired 注解也可以应用在集合属性上, 此时 Spring 读取该集合的类型信息, 然后自动装配所有与之兼容的 Bean. 
				  @Authwired 注解用在 java.util.Map 上时, 若该 Map 的键值为 String, 那么 Spring 将自动装配与之 Map 值类型兼容的 Bean, 此时 Bean 的名称作为键值
				  
				  ***Extra:
					Spring 还支持 @Resource 和 @Inject 注解，这两个注解和 @Autowired 注解的功用类似
					@Resource 注解要求提供一个 Bean 名称的属性，若该属性为空，则自动采用标注处的变量或方法名作为 Bean 的名称
					@Inject 和 @Autowired 注解一样也是按类型匹配注入的 Bean， 但没有 reqired 属性
					建议使用 @Autowired 注解
		
		2) Bean的配置方式: 通过全类名(反射)、通过工厂方法(静态工厂方法&实例工厂方法)、FactoryBean
			- 通过工厂方法来配置bean
				*** <!-- 通过静态工厂方法来配置bean，注意不是配置静态工厂方法实例，而是配置bean实例 -->
					<!-- 
						class属性 : 指向静态工厂方法的名字
						constructor-arg: 如果工厂方法需要传入参数，则使用constructor-arg来配置参数
					 -->
					<bean id="car1"
						class="com.nku.mason.spring.beans.factory.StaticCarFactory"
						factory-method="getCar">
						<constructor-arg value="audi"></constructor-arg>	
					</bean>
			
				*** <!-- 配置工厂的实例 -->
					<bean id="carFactory" class="com.nku.mason.spring.beans.factory.InstanceCarFactory"></bean>
					
					<!-- 通过实例工厂方法来配置bean -->
					<!-- 
						factory-bean 属性: 指向实例工厂方法的bean
						factory-method: 指向静态工厂方法的名字
						constructor-arg: 如果工厂方法需要传入参数，则使用constructor-arg来配置参数
					 -->
					<bean id="car2" factory-bean="carFactory" factory-method="getCar">
						<constructor-arg value="ford"></constructor-arg>
					</bean>
					
			- 通过FactoryBean配置bean
				自定义的FactoryBean需要实现Spring提供的FactoryBean<T> 接口,
				eg:
				public class CarFactoryBean implements FactoryBean<Car> {
					private String brand;
					
					/**
					 * @param brand the brand to set
					 */
					public void setBrand(String brand) {
						this.brand = brand;
					}
					
					/**
					 * 返回bean的对象
					 */
					@Override
					public Car getObject() throws Exception {
						return new Car("BMW",50000);
					}

					/**
					 * 返回bean的类型
					 */
					public Class<?> getObjectType() {
						return Car.class;
					}

					@Override
					public boolean isSingleton() {
						return true;
					}

				}
			
		3) IOC容器: BeanFactory & ApplicationContext
		
		4) 依赖注入的方式: 属性注入；构造器注入
			a) 属性注入:即通过 setter 方法注入Bean 的属性值或依赖的对象
				<bean id="person" class="com.nku.mason.spring.beans.Person">
					<property name="name" value="TOM"></property>
					<property name="age" value="24"></property>
					<property name="car" ref="car"></property>
					<property name="car.maxSpeed" value="560"></property>
				</bean>
				
			b) 构造器注入:
				- 通过构造方法注入Bean 的属性值或依赖的对象，它保证了 Bean 实例在实例化后就可以使用。
				- 构造器注入在 <constructor-arg> 元素里声明属性, <constructor-arg> 中没有 name 属性
					eg: <bean id="car" class="com.nku.mason.spring.beans.Car">
							<constructor-arg value="Audi" type="java.lang.String" index="0"></constructor-arg>
							<constructor-arg value="ShangHai"></constructor-arg>
							<constructor-arg >
								<value>456</value>
							</constructor-arg>
						</bean>
					***使用构造器注入属性值可以指定参数的位置和类型来区分重载的构造器。
					***字面值： - 可用字符串表示的值，可以通过 <value> 元素标签或 value 属性进行注入。
								- 基本数据类型及其封装类、String 等类型都可以采取字面值注入的方式。
								- 若字面值中包含特殊字符，可以使用 <![CDATA[]]> 把字面值包裹起来。
		
		5) Bean之间的相互引用
			组成应用程序的 Bean 经常需要相互协作以完成应用程序的功能. 要使 Bean 能够相互访问, 
			就必须在 Bean 配置文件中指定对 Bean 的引用。
			
			- 在 Bean 的配置文件中, 可以通过 <ref> 元素或 ref  属性为 Bean 的属性或构造器参数指定对 Bean 的引用. 
			
			- 也可以在属性或构造器里包含 Bean 的声明, 这样的 Bean 称为内部 Bean (内部bean不能被外部引用，所以加id也没卵用)
				<bean id="person" class="com.nku.mason.spring.beans.Person">
					<property name="name" value="TOM"></property>
					<property name="age" value="24"></property>
					<!-- 使用property的ref属性可以建立bean之间的引用关系 -->
					<!-- 
					<property name="car" ref="car"></property>
					 -->
					<!-- 内部bean -->
					<property name="car">
						<bean class="com.nku.mason.spring.beans.Car">
							<constructor-arg value="Ford"></constructor-arg>
							<constructor-arg value="Beijing"></constructor-arg>
							<constructor-arg value="789"></constructor-arg>
						</bean>
					</property>
				</bean>
		
			- 可以使用专用的 <null/> 元素标签为 Bean 的字符串或其它对象类型的属性注入 null 值
				
			- 和 Struts、Hiberante 等框架一样，Spring 支持级联属性的配置。
				<!-- 为级联属性赋值, 注意属性需要先初始化后才可以为级联属性赋值，否则会有异常，和Struts2不同。 -->
				<property name="car" ref="car"></property>
				<property name="car.maxSpeed" value="260"></property>
		
		6) 集合属性
			- 在 Spring中可以通过一组内置的 xml 标签(例如: <list>, <set> 或 <map>) 来配置集合属性.
			
			- 配置 java.util.List 类型的属性, 需要指定 <list>  标签, 在标签里包含一些元素. 
				这些标签可以通过 <value> 指定简单的常量值, 通过 <ref> 指定对其他 Bean 的引用. 
				通过<bean> 指定内置 Bean 定义. 通过 <null/> 指定空元素. 甚至可以内嵌其他集合.
				
			- 数组的定义和 List 一样, 都使用 <list>
			
			- 配置 java.util.Set 需要使用 <set> 标签, 定义元素的方法与 List 一样.
			
			***Java.util.Map 通过 <map> 标签定义, <map> 标签里可以使用多个 <entry> 作为子标签. 每个条目包含一个键和一个值. 
				必须在 <key> 标签里定义键
				因为键和值的类型没有限制, 所以可以自由地为它们指定 <value>, <ref>, <bean> 或 <null> 元素. 
				可以将 Map 的键和值作为 <entry> 的属性定义: 简单常量使用 key 和 value 来定义;
				Bean 引用通过 key-ref 和 value-ref 属性定义
				使用 <props> 定义 java.util.Properties, 该标签使用多个 <prop> 作为子标签. 每个 <prop> 标签必须定义 key 属性.
				
				eg:
				<!-- 配置独立的集合bean，以供多个bean进行引用,需要导入util命名空间 -->
				<util:list id="cars">
					<ref bean="car"/>
				</util:list>
				
				<bean id="person4" class="com.nku.mason.spring.beans.collection.Person">
					<property name="name" value="Jack"></property>
					<property name="age" value="56"></property>
					<property name="cars" ref="cars"></property>
				</bean>
		
		7) P命名空间(将<property>转化为bean的一个属性)
			为了简化 XML 文件的配置，越来越多的 XML 文件采用属性而非子元素配置信息。
			Spring 从 2.5 版本开始引入了一个新的 p 命名空间，可以通过 <bean> 元素属性的方式配置 Bean 的属性。
			使用 p 命名空间后，基于 XML 的配置方式将进一步简化
			
			eg:
			<!-- 通过p命名空间为bean的属性赋值，需要先导入p命名空间 -->
			<bean id="person5" class="com.nku.mason.spring.beans.collection.Person" p:name="Queen" p:age="78" p:cars-ref="cars"></bean>
		
		8) 自动装配 (实际中并不用,除了整合第三方框架时)
			***Spring IOC 容器可以自动装配 Bean. 需要做的仅仅是在 <bean> 的 autowire 属性里指定自动装配的模式
			- byType(根据类型自动装配): 若 IOC 容器中有多个与目标 Bean 类型一致的 Bean. 在这种情况下, 
			  Spring 将无法判定哪个 Bean 最合适该属性, 所以不能执行自动装配.
			  
			- byName(根据名称自动装配): 必须将目标 Bean 的名称和属性名设置的完全相同.
			
			- constructor(通过构造器自动装配): 当 Bean 中存在多个构造器时, 此种自动装配方式将会很复杂. 不推荐使用
		缺点:
			- 在 Bean 配置文件里设置 autowire 属性进行自动装配将会装配 Bean 的所有属性. 然而, 若只希望装配个别属性时, 
				autowire 属性就不够灵活了. 
			- autowire 属性要么根据类型自动装配, 要么根据名称自动装配, 不能两者兼而有之.
			- 一般情况下，在实际的项目中很少使用自动装配功能，因为和自动装配功能所带来的好处比起来，明确清晰的配置文档更有说服力一些

		9) bean之间的关系
			***继承
			- Spring 允许继承 bean 的配置, 被继承的 bean 称为父 bean. 继承这个父 Bean 的 Bean 称为子 Bean
			- 子 Bean 从父 Bean 中继承配置, 包括 Bean 的属性配置
			- 子 Bean 也可以覆盖从父 Bean 继承过来的配置
			- 父 Bean 可以作为配置模板, 也可以作为 Bean 实例. 若只想把父 Bean 作为模板, 可以设置 <bean> 的abstract 属性为 true, 这样 Spring 将不会实例化这个 Bean
			- 并不是 <bean> 元素里的所有属性都会被继承. 比如: autowire, abstract 等.
			- 也可以忽略父 Bean 的 class 属性, 让子 Bean 指定自己的类, 而共享相同的属性配置. 但此时 abstract 必须设为 true

			***依赖
			- Spring 允许用户通过 depends-on 属性设定 Bean 前置依赖的Bean，前置依赖的 Bean 会在本 Bean 实例化之前创建好
			- 如果前置依赖于多个 Bean，则可以通过逗号，空格或的方式配置 Bean 的名称
		
		10) bean的作用域
			<!-- 
				使用bean的scope属性来配置bean的作用域:
					singleton: 默认值. 容器初始化时创建bean实例，在整个容器的生命周期内只创建这一个bean. 单例的
					prototype: 原型的. 容器初始化时不创建bean的实例，而在每次请求时都创建一个新的Bean的实例，并返回
					session%request: 对应域对象的session和request，用的比较少
			 -->
			<bean id="car" class="com.nku.mason.spring.beans.autowire.Car">
				<property name="brand" value="Audi"></property>
				<property name="price" value="200000"></property>
			</bean>
		
		11) 使用外部的属性文件
			- 在配置文件里配置 Bean 时, 有时需要在 Bean 的配置里混入系统部署的细节信息(例如: 文件路径, 数据源配置信息等). 
			  而这些部署细节实际上需要和 Bean 配置相分离
			- Spring 提供了一个 PropertyPlaceholderConfigurer 的 BeanFactory 后置处理器, 这个处理器允许用户将 Bean 配置的
			  部分内容外移到属性文件中. 可以在 Bean 配置文件里使用形式为 ${var} 的变量, PropertyPlaceholderConfigurer 从属性
			  文件里加载属性, 并使用这些属性来替换变量.
            -Spring 还允许在属性文件中使用 ${propName}，以实现属性之间的相互引用。

	3. Spring表达式语言: SpEL
		1) 简介
			- Spring 表达式语言（简称SpEL）：是一个支持运行时查询和操作对象图的强大的表达式语言。
			- 语法类似于 EL：SpEL 使用 #{…} 作为定界符，所有在大框号中的字符都将被认为是 SpEL
			- SpEL 为 bean 的属性进行动态赋值提供了便利
			- 通过 SpEL 可以实现：
				* 通过 bean 的 id 对 bean 进行引用
				* 调用方法以及引用对象中的属性
				* 计算表达式的值
				* 正则表达式的匹配
		2) 字面量，意义不大.....
		
		3) 引用 Bean、属性和方法
			<bean id="address" class="com.nku.mason.spring.beans.spel.Address">
				<!-- 使用spel为属性赋一个字面值 -->
				<property name="city" value="#{'Beijing'}"></property>
				<property name="street" value="WudaoKou"></property>
			</bean>

			<bean id="car" class="com.nku.mason.spring.beans.spel.Car">
				<property name="brand" value="Audi"></property>
				<property name="price" value="500000"></property>
				<!-- 使用 SpEL引用类的静态属性-->
				<property name="tyrePerimeter" value="#{T(java.lang.Math).PI * 80}"></property>
			</bean>
			
			<bean id="person" class="com.nku.mason.spring.beans.spel.Person">
				<!-- 使用SpEL来引用其他的bean -->
				<property name="car" value="#{car}"></property>
				<!-- 使用SpEl来引用其他bean的属性 -->
				<property name="city" value="#{address.city}"></property>
				<!-- 在SpEL中使用运算符 -->
				<property name="info" value="#{car.price > 30000 ? '金领' : '白领'}"></property>
				<property name="name" value="Tom"></property>
			</bean>
	
	4. IOC容器中Bean的声明周期
		1) 简介
			- Spring IOC 容器可以管理 Bean 的生命周期, Spring 允许在 Bean 生命周期的特定点执行定制的任务. 
			- Spring IOC 容器对 Bean 的生命周期进行管理的过程:
				* 通过构造器或工厂方法创建 Bean 实例
				* 为Bean 的属性设置值和对其他 Bean 的引用
				* 调用 Bean 的初始化方法
				* Bean 可以使用了
				* 当容器关闭时, 调用 Bean 的销毁方法
				* 在 Bean 的声明里设置 init-method 和 destroy-method 属性, 为 Bean 指定初始化和销毁方法.

		2) 可以对Bean的生命周期进行更细粒度的设定
			- 创建 Bean 后置处理器
				* Bean 后置处理器允许在调用初始化方法前后对 Bean 进行额外的处理.
				* Bean 后置处理器对 IOC 容器里的所有 Bean 实例逐一处理, 而非单一实例. 其典型应用是: 
						检查 Bean 属性的正确性或根据特定的标准更改 Bean 的属性.
				* 对Bean 后置处理器而言, 需要实现org.springframework.beans.factory.config Interface BeanPostProcessor接口. 
				* 在初始化方法被调用前后, Spring 将把每个 Bean 实例分别传递给上述接口的以下两个方法:
					postProcessAfterInitialization(Object bean, String beanName)
					postProcessBeforeInitialization(Object bean, String beanName)
		
		    eg:	<!-- 实现BeanPostProcessor 接口，并具体提供两个方法的实现
					postProcessAfterInitialization(Object bean, String beanName): init-method 之前被调用
					postProcessBeforeInitialization(Object bean, String beanName): init-method 之后被调用
					
					bean: bean 实例本身
					beanName: IOC容器配置的bean的名字。
					返回值: 实际上返回给用户的那个bean，注意: 可以在以上两个方法中修改返回的bean，甚至返回一个自己创建的bean
				 -->
				<!-- 配置bean的后置处理器 , 不需要配置id,IOC容器自动识别是一个 BeanPostProcessor-->
				<bean class="com.nku.mason.spring.beans.cycle.MyBeanPostProcessor"></bean>
		
	5) 泛型依赖注入
		1) 父类之间的依赖关系，会在子类中自动添加泛型实际类型的依赖关系

/************************************************************************************************************************/		
	//Spring AOP
	
	//前言:动态代理举例
	/******************************************************************************/
	import java.lang.reflect.InvocationHandler;
	import java.lang.reflect.Method;
	import java.lang.reflect.Proxy;
	import java.util.Arrays;
	
	public class ArithmeticCalculatorLoggingProxy {
	
	//要代理的对象
	ArithmeticCalculator target = new ArithmeticCalculatorImpl();
	
	public ArithmeticCalculatorLoggingProxy(ArithmeticCalculator target){
		this.target = target;
	}
	
	public ArithmeticCalculator getLoggingCalculatorProxy(){
		
			//代理对象由哪个类加载器负责加载
			ClassLoader loader = target.getClass().getClassLoader();
			//代理对象的类型，即其中有哪些方法
			Class[] interfaces = new Class[] {ArithmeticCalculator.class};
			
			InvocationHandler h = new InvocationHandler() {
				
				/**
				 * proxy: 正在返回的那个代理对象，一般情况下，在invoke方法中都不使用该对象。
				 * method: 正在被调用的方法
				 * args: 调用方法时，传入的参数
				 */
				@Override
				public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
					String methodName = method.getName();
					//日志
					System.out.println("The method " + methodName + " begins with " + Arrays.asList(args));
					Object result = method.invoke(target, args);
					//日志
					System.out.println("The method " + methodName + " ends with " + result);
					return 0;
				}
			};
			
			return (ArithmeticCalculator) Proxy.newProxyInstance(loader, interfaces, h);
		}
	}
	/******************************************************************************/
	
	1. Spring AOP相关介绍
		1) 为何需要AOP？
			- 代码混乱：越来越多的非业务需求(日志和验证等)加入后, 原有的业务方法急剧膨胀.  
			            每个方法在处理核心逻辑的同时还必须兼顾其他多个关注点. 
			- 代码分散: 以日志需求为例, 只是为了满足这个单一需求, 就不得不在多个模块（方法）里多次重复相同的日志代码.
			            如果日志需求发生变化, 必须修改所有模块.
		
		2) 简介
			- AOP(Aspect-Oriented Programming, 面向切面编程): 是一种新的方法论, 是对传统 OOP(Object-Oriented Programming, 面向对象编程) 的补充.
			- AOP 的主要编程对象是切面(aspect), 而切面模块化横切关注点.
			- 在应用 AOP 编程时, 仍然需要定义公共功能, 但可以明确的定义这个功能在哪里, 以什么方式应用, 并且不必修改受影响的类.
  			  这样一来横切关注点就被模块化到特殊的对象(切面)里.
			- AOP 的好处:
			   * 每个事物逻辑位于一个位置, 代码不分散, 便于维护和升级
			   * 业务模块更简洁, 只包含核心业务代码.
		
		3) AOP 术语
			切面(Aspect):  横切关注点(跨越应用程序多个模块的功能)被模块化的特殊对象
			通知(Advice):  切面必须要完成的工作
			目标(Target):  被通知的对象
			代理(Proxy):   向目标对象应用通知之后创建的对象
			连接点（Joinpoint）：程序执行的某个特定位置：如类某个方法调用前、调用后、方法抛出异常后等。
			                     连接点由两个信息确定：方法表示的程序执行点；相对点表示的方位。例如 ArithmethicCalculator#add() 
								 方法执行前的连接点，执行点为 ArithmethicCalculator#add()； 方位为该方法执行前的位置
			切点（pointcut）：每个类都拥有多个连接点：例如 ArithmethicCalculator 的所有方法实际上都是连接点，即连接点是程序类
			                  中客观存在的事务。AOP 通过切点定位到特定的连接点。类比：连接点相当于数据库中的记录，切点相当于
							  查询条件。切点和连接点不是一对一的关系，一个切点匹配多个连接点，
							  切点通过 org.springframework.aop.Pointcut 接口进行描述，它使用类和方法作为连接点的查询条件。
		
		4) Spring AOP
			AspectJ：Java 社区里最完整最流行的 AOP 框架.		//其实Spring自身也有AOP的实现，但没有这个好用
			在 Spring2.0 以上版本中, 可以使用基于 AspectJ 注解或基于 XML 配置的 AOP
		
			a) 加入 jar 包:
				com.springsource.org.aopalliance-1.0.0.jar
				com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
				org-apache-commons-logging.jar
				spring-aop-4.2.6.RELEASE.jar
				spring-aspects-4.2.6.RELEASE.jar
				spring-beans-4.2.6.RELEASE.jar
				spring-context-4.2.6.RELEASE.jar
				spring-core-4.2.6.RELEASE.jar
				spring-expression-4.2.6.RELEASE.jar
		
			b) 在配置文件中加入AOP的命名空间
				
				xmlns:aop="http://www.springframework.org/schema/aop"
		
			c) 基于注解的方式
				① 在配置文件中加入如下配置:
					<!-- 使AspectJ 注解起作用 : 自动为匹配的类生成代理对象-->
					<aop:aspect-autoproxy></aop:aspect-autoproxy>
				② 把横切关注点的代码抽象到切面的类中。
					i.  切面首先是一个IOC中的bean，即加入@Component注解
					ii. 切面还需加入 @Aspect 注解
				
				③ 在类中声明各种通知: 声明一个方法，在方法前加入@Before注解
					AspectJ 支持 5 种类型的通知注解: //例子见代码
						@Before: 前置通知, 在方法执行之前执行
						@After: 后置通知, 在方法执行之后执行 
						@AfterReturning: 返回通知, 在方法返回结果之后执行
						@AfterThrowing: 异常通知, 在方法抛出异常之后
						@Around: 环绕通知, 围绕着方法执行
				
					利用方法签名编写 AspectJ 切入点表达式
		
				④ 可以在通知方法中声明一个类型为 JoinPoint 的参数. 然后就能访问链接细节. 如方法名称和参数值. 
					eg：
						@Component
						@Aspect
						public class LoggingAspect {
							
							//声明该方法是一个前置通知:在目标方法开始之前执行
							@Before("execution(public int com.nku.mason.spring.aop.impl.ArithmeticCalculatorImpl.*(int , int))")
							public void beforeMethod(JoinPoint joinPoint){
								String methodName = joinPoint.getSignature().getName();
								List<Object> args = Arrays.asList(joinPoint.getArgs());
								System.out.println("The method:" + methodName + " begins with :" + args);
							}
							
						}																							
		
			d) 指定切面的优先级
				@Order(2)	//使用该注解指定切面的优先级，值越小优先级越高
		
			e) 重用切点表达式
				eg:	/**
					 * 定义一个方法用于声明切入点表达式，一般的，该方法中再不需要添加其他的代码。
					 * @param joinPoint
					 * 后面的其他通知，直接使用方法名来引用切入点表达式
					 */
					@Pointcut("execution(public int com.nku.mason.spring.aop.impl.ArithmeticCalculatorImpl.*(int , int)))")
					public void declareJointPointExpression(){}
					
					//声明该方法是一个前置通知:在目标方法开始之前执行
					@Before("declareJointPointExpression()")
					public void beforeMethod(JoinPoint joinPoint){
						String methodName = joinPoint.getSignature().getName();
						List<Object> args = Arrays.asList(joinPoint.getArgs());
						System.out.println("The method:" + methodName + " begins with :" + args);
					}
		
			f) 基于xml配置文件的方式
				<!-- 配置bean -->
				<bean id="arithmeticCalculator"
					class="com.nku.mason.spring.aop.xml.ArithmeticCalculatorImpl"></bean>
					
				<!-- 配置切面的bean -->
				<bean id="loggingAspect"
					class="com.nku.mason.spring.aop.xml.LoggingAspect"></bean>
				<bean id="validationAspect"
					class="com.nku.mason.spring.aop.xml.ValidationAspect"></bean>
					
				<!-- 配置AOP -->
				<aop:config>
					<!-- 配置切点表达式 -->
					<aop:pointcut expression="execution(* com.nku.mason.spring.aop.xml.ArithmeticCalculator.*(int, int))" 
						id="pointcut"/>
					<!-- 配置切面和通知 -->
					<aop:aspect ref="loggingAspect" order="2">
						<aop:before method="beforeMethod" pointcut-ref="pointcut"/>
						<aop:after method="afterMethod" pointcut-ref="pointcut"/>
						<aop:after-throwing method="afterThrowing" pointcut-ref="pointcut" throwing="ex"/>
						<aop:after-returning method="afterReturning" pointcut-ref="pointcut" returning="result"/>
					</aop:aspect>
					<aop:aspect ref="validationAspect" order="1">
						<aop:after method="validateArgs" pointcut-ref="pointcut"/>
					</aop:aspect>
				</aop:config>
		
	2. Spring的JdbcTemplate 简介	
		为了使 JDBC 更加易于使用, Spring 在 JDBC API 上定义了一个抽象层, 以此建立一个 JDBC 存取框架.
		作为 Spring JDBC 框架的核心, JDBC 模板的设计目的是为不同类型的 JDBC 操作提供模板方法. 每个模板方法都能控制整个过程,
		并允许覆盖过程中的特定任务. 通过这种方式, 可以在尽可能保留灵活性的情况下, 将数据库存取的工作量降到最低.

		例子:见Spring-3
		
		*在JDBCTemplate中使用具名参数
			@Test
			public void test() throws SQLException{
				DataSource datasource = ctx.getBean(DataSource.class);
				System.out.println(datasource.getConnection());
			}
			/**
			 * 使用具名参数时，可以使用update(String sql, SqlParameterSource paramSource)方法进行更新操作
			 * 1. SQL 语句中的参数名和类的属性一致!
			 * 2. 使用SqlParameterSource 的  BeanPropertySqlParameterSource 实现类作为参数.
			 */
			@Test
			public void testNamedParameterJdbcTemplate2(){
				
			}
			
			/**
			 * 可以为参数起名字
			 * 1. 好处: 若有多个参数，则不用再去对应位置，直接对应参数名，便于维护
			 * 2. 缺点: 较为麻烦
			 */
			@Test
			public void testNamedparameterJdbcTemplate(){
				String sql = "INSERT INTO test1 (name) VALUES(:n)";
				
				Map<String, Object> paramMap = new HashMap<>();
				paramMap.put("n", "Aloha");
				
				nJdbcTemplate.update(sql, paramMap);		
			}
		
	3. Spring 中的事物管理
		事务管理是企业级应用程序开发中必不可少的技术,  用来确保数据的完整性和一致性. 
		事务就是一系列的动作, 它们被当做一个单独的工作单元. 这些动作要么全部完成, 要么全部不起作用
		
		事务的四个关键属性(ACID)
		原子性(atomicity): 事务是一个原子操作, 由一系列动作组成. 事务的原子性确保动作要么全部完成要么完全不起作用.
		一致性(consistency): 一旦所有事务动作完成, 事务就被提交. 数据和资源就处于一种满足业务规则的一致性状态中.
		隔离性(isolation): 可能有许多事务会同时处理相同的数据, 因此每个事物都应该与其他事务隔离开来, 防止数据损坏.
		持久性(durability): 一旦事务完成, 无论发生什么系统错误, 它的结果都不应该受到影响. 通常情况下, 事务的结果被写到持久化存储器中.
		
		作为企业级应用程序框架, Spring 在不同的事务管理 API 之上定义了一个抽象层. 而应用程序开发人员不必了解底层的事务管理 API, 
		就可以使用 Spring 的事务管理机制.
		
		Spring 既支持编程式事务管理, 也支持声明式的事务管理. 
		编程式事务管理: 将事务管理代码嵌入到业务方法中来控制事务的提交和回滚. 在编程式管理事务时, 
		必须在每个事务操作中包含额外的事务管理代码. 
		
		声明式事务管理: 大多数情况下比编程式事务管理更好用. 它将事务管理代码从业务方法中分离出来, 
		以声明的方式来实现事务管理. 事务管理作为一种横切关注点, 可以通过 AOP 方法模块化.
		Spring 通过 Spring AOP 框架支持声明式事务管理.
	
		**声明式事务的使用:
		1) 在Spring的配置文件中，配置好要扫描的包，让注解机制能够起作用。
			<!-- 配置扫描的包 -->
			<context:component-scan base-package="com.nku.mason.spring"></context:component-scan>
		
		2) 在Spring的配置文件中配置开启事务管理器
			<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
				<property name="dataSource" ref="dataSource"></property>
			</bean>
		
		3) 在作为事务的方法上加上@Transactional注解
		
		
		** 事务具有的属性:
			
			***并发事务所导致的问题：
				当同一个应用程序或者不同应用程序中的多个事务在同一个数据集上并发执行时, 可能会出现许多意外的问题
				并发事务所导致的问题可以分为下面三种类型:
				
				脏读: 对于两个事物 T1, T2, T1  读取了已经被 T2 更新但 还没有被提交的字段. 之后, 若 T2 回滚, T1读取的内容就是临时且无效的.
				不可重复读:对于两个事物 T1, T2, T1  读取了一个字段, 然后 T2 更新了该字段. 之后, T1再次读取同一个字段, 值就不同了.
				幻读:对于两个事物 T1, T2, T1  从一个表中读取了一个字段, 然后 T2 在该表中插入了一些新的行. 之后, 如果 T1 再次读取同一个表, 就会多出几行.
		
			/**
			 * 测试事务的传播行为
			 * 1. 使用propagation指定事物的传播行为，即当前的事务方法被另一个事务方法调用时
			 * 如何使用事务，默认取值为REQUIRED，即,使用调用方法的事务
			 * 
			 * 2. REQUIRES_NEW: 使用自己的事务,调用的事务方法的事务被挂起
			 * 
			 * 3. 使用isolation指定事务的隔离级别，最常用的取值为READ_COMMITTED(防止脏读，可能发生不可重复读和幻读)
			 * 
			 * 4. 默认情况下Spring的声明式事务对所有的运行时异常进行回滚，也可以通过对应的属性进行设置
			 * 如:noRollbackFor={UserAccountException.class}
			 * 通常情况下，取默认值即可
			 * 
			 * 5. 使用readOnly指定事务是否为只读。(设置为只读时，数据库引擎会对事务做优化，因为没有写，所以可以不加锁，使读取操作变得更快)
			 *
			 * 6. 使用timeout指定强制回滚之前，事务可以占用的时间
			 */
			例如:
			@Transactional(propagation=Propagation.REQUIRES_NEW,
					isolation=Isolation.READ_COMMITTED,
					readOnly=false,
					timeout=3)
			@Override
			public void purchase(String username, String isbn) {
				//1. 获取书的单价
				int price = bookShopDao.findBookPriceByISBN(isbn);
				
				//2. 更新书的库存
				bookShopDao.updateBookStock(isbn);
				
				//3. 更新用户余额
				bookShopDao.updateUserAccount(username, price);
			}	
		
		**XML配置事务:
		1) 在编写好相关类后，在Spring的配置文件中做如下配置，eg
		
			<!-- 配置bean -->
			<bean id="bookShopDao" class="com.nku.mason.spring.jdbc.transactionManager.xml.BookShopDaoImpl">
				<property name="jdbcTemplate" ref="jdbcTemplate"></property>
			</bean>
			
			<bean id="bookShopService" class="com.nku.mason.spring.jdbc.transactionManager.xml.service.impl.BookShopServiceImpl">
				<property name="bookShopDao" ref="bookShopDao"></property>
			</bean>
			
			<bean id="cashier" class="com.nku.mason.spring.jdbc.transactionManager.xml.service.impl.CashierImpl">
				<property name="bookShopService" ref="bookShopService"></property>
			</bean>
			
			<!-- 1. 配置事务管理器 -->
			<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
				<property name="dataSource" ref="dataSource"></property>
			</bean>
			
			<!-- 2. 配置事务属性 -->
			<tx:advice id="txAdvice" transaction-manager="transactionManager">
				<!-- 根据方法名指定事务的属性 -->		
				<tx:attributes>
					<tx:method name="purchase" propagation="REQUIRES_NEW"/>
					<tx:method name="*"/>
				</tx:attributes>
			</tx:advice>
			
			<!-- 3. 配置事务切入点 -->
			<aop:config>
				<aop:pointcut expression="execution(* com.nku.mason.spring.jdbc.transactionManager.xml.Service.*.*(..))" 
					id="txPointCut"/>
				<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
			</aop:config>
		
	4. Spring整合Hibernate
	    ** Spring 整合Hibernate整合什么?
		1) 由IOC容器来生成Hibernate的SessionFactory
		2) 让Hibernate使用上Spring的声明式事务
	
		**整合步骤:
		1) 先加入Hibernate
			① 添加相应的jar包
			② 添加Hibernate的配置文件: hibernate.cfg.xml
				<?xml version="1.0" encoding="UTF-8"?>
				<!DOCTYPE hibernate-configuration PUBLIC
						"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
						"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
				<hibernate-configuration>
					<session-factory>
						<!-- 配置Hibernate的基本属性 -->
						<!-- 1. 数据源需配置到IOC容器中，所以在此处不再需要配置数据源 -->
						<!-- 2. 关联的.hbm.xml也在IOC容器中配置SessionFactory实例时再进行配置 -->
						<!-- 3. 配置Hibernate的基本属性: 方言，SQL显示及格式化, 生成数据表的策略及二级缓存等 -->
						<property name="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>
						
						<property name="hibernate.show_sql">true</property>
						<property name="hibernate.format_sql">true</property>
						
						<!-- 自动生成数据表 -->
						<property name="hibernate.hbm2ddl.auto">update</property>
						
						<!-- 配置Hibernate二级缓存相关 -->
						<!-- 略 -->
					</session-factory>
				</hibernate-configuration>
			③ 编写了持久化类对应的.hbm.xml文件
			
		2) 再加入Spring
			①加入jar包
			②加入Spring配置文件
			<!-- 配置自动扫描的包 -->
			<context:component-scan base-package="com.nku.mason.spring.hibernate"></context:component-scan>

			<!-- 配置数据源 -->
			<!-- 导入资源文件 -->
			<context:property-placeholder location="classpath:db.properties"/>
			
			<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
				<property name="user" value="${jdbc.user}"></property>
				<property name="password" value="${jdbc.password}"></property>
				<property name="driverClass" value="${jdbc.driverClass}"></property>
				<property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
				
				<property name="initialPoolSize" value="${jdbc.initPoolSize}"></property>
				<property name="maxPoolSize" value="${jdbc.maxPoolSize}"></property>
			</bean>
			
			<!-- 配置Hibernate的SessionFactory 实例 : 通过Spring提供的LocalSessionFactoryBean进行配置-->
			<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
				<!-- 配置数据源属性 -->
				<property name="dataSource" ref="dataSource"></property>
				<!-- 配置Hibernate配置文件及名称 -->
				<!-- 
				<property name="configLocation" value="classpath:hibernate.cfg.xml"></property>
				 -->
				<!-- 使用hibernateProperties属性来配置Hibernate原生的属性 -->
				<property name="hibernateProperties">
					<props >
						<prop key="hibernate.dialect">org.hibernate.dialect.MySQLInnoDBDialect</prop>
						<prop key="hibernate.show_sql">true</prop>
						<prop key="hibernate.format_sql">true</prop>
						<prop key="hibernate.hbm2ddl.auto">update</prop>
					</props>
				</property>
				<!-- 配置Hibernate映射文件的位置及名称，可以使用通配符 -->
				<property name="mappingLocations" value="classpath:com/nku/mason/spring/hibernate/entities/*.hbm.xml"></property>
			</bean>
			
			<!-- 配置Spring的声明式事务 -->
			<!-- 1. 配置事务管理器 -->
			<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
				<property name="sessionFactory" ref="sessionFactory"></property>
			</bean>
			
			<!-- 2. 配置事务属性 -->
			<tx:advice id="txAdvice" transaction-manager="transactionManager">
				<tx:attributes>
					<tx:method name="get*" read-only="true"/>
					<tx:method name="*"/>
				</tx:attributes>
			</tx:advice>
			
			<!-- 3. 配置事务切点，并把切点和事务属性关联起来 -->
			<aop:config>
				<aop:pointcut expression="execution(* com.nku.mason.spring.hibernate.service.*.*(..))"
					id="txPointCut"/>
				<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
			</aop:config>
		
		3) 整合
			即配置不同的事务管理器，(spring中对不同的持久化框架有不同的事务管理器)
			
		4) 实际编写代码
		
	5. Spring整合Struts2
		1) Spirng如何在Web应用中使用?
			①jar包: spring-web和spring-webmvc包需要加入
			②Spring的配置文件并没什么不同
			③如何创建IOC容器？
				a) 非web应用在main方法中直接创建
				b) Web应用应该在web应用被服务器加载时就创建IOC容器:
					在ServletContextListener#contextIntialized(ServletContextEvent sce)方法中创建IOC容器
				c) 在Web应用的其他组件中如何来访问IOC容器呢?
					在ServletContextListener#contextIntialized(ServletContextEvent sce)方法中创建IOC容器后，可以把其放在ServletContext(即application域)的一个属性中
				d) 实际上,Spring配置文件的名字和位置应该也是可以配置的,将其配置到当前web应用的初始化参数中较为合适		
		
		2) Spring本身提供了如下监听器，实现了1)里的功能
			<!-- 启动IOC容器的ServletContextListener -->
			<listener>
				<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
			</listener>
		
		3) 总结(Web环境下使用Spring):
			① 需要加入额外的jar包:
				spring-web和spring-webmvc包
				
			② 需要在web.xml文件中加入如下配置：
				<!-- 配置Spring配置文件的名称和位置 -->
				<context-param>
					<param-name>contextConfigLocation</param-name>
					<param-value>classpath:applicationContext.xml</param-value>
				</context-param>

				<!-- 启动IOC容器的ServletContextListener -->
				<listener>
					<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
				</listener>
		
		4) 整合Struts2
			① 整合的目标: 使IOC容器来管理struts2的Action!!!
			② 如何进行整合?
				a) 正常加入struts2
				b) 配置web.xml文件，配置struts2的filter
					<filter>
						<filter-name>struts2</filter-name>
						<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
					</filter>

					<filter-mapping>
						<filter-name>struts2</filter-name>
						<url-pattern>/*</url-pattern>
					</filter-mapping>
					*/
				c) 在Spring的IOC容器中配置Struts2的Action,注意: 在IOC容器中配置Struts2的Action时，一定要加上scope为prototype
				d) 配置struts2的配置文件,pring整合struts2时，在Struts2中配置的Spring的Action的class需要指向IOC容器中该bean的id
				e) 加入struts2-spring-plugin包		
					整合原理，通过添加struts2-spring-plugin包后，struts2会先从IOC容器中获取Action的实例,否则再反射创建	
		
		
		
		
		
		
		
		
		
		
		
		
		
		
		
		
		
		